/**
 * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springblade.modules.policy.service.impl;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.common.tool.MASUtil;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.enterprise.entity.Enterprise;
import org.springblade.modules.enterprise.service.IEnterpriseService;
import org.springblade.modules.enterprise.vo.EnterprisePushVO;
import org.springblade.modules.enterprise.vo.EnterpriseVO;
import org.springblade.modules.policy.entity.Policy;
import org.springblade.modules.policy.entity.PolicyDraw;
import org.springblade.modules.policy.mapper.PolicyDrawMapper;
import org.springblade.modules.policy.service.IPolicyDrawMaterialService;
import org.springblade.modules.policy.service.IPolicyDrawProcessService;
import org.springblade.modules.policy.service.IPolicyDrawService;
import org.springblade.modules.policy.service.IPolicyService;
import org.springblade.modules.policy.vo.PolicyDrawPushVO;
import org.springblade.modules.policy.vo.PolicyDrawVO;
import org.springblade.modules.policy.vo.PolicyPushVO;
import org.springblade.modules.sga.vo.SgaPolicyDrawPushVo;
import org.springblade.modules.sga.vo.SgaPolicyDrawVO;
import org.springblade.modules.system.entity.DictItem;
import org.springblade.modules.system.service.IDictItemService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.Valid;
import java.lang.reflect.Field;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 服务实现类
 *
 * @author Blade
 * @since 2022-07-25
 */
@Service
public class PolicyDrawServiceImpl extends BaseServiceImpl<PolicyDrawMapper, PolicyDraw> implements IPolicyDrawService {

	@Autowired
	private IPolicyDrawProcessService policyDrawProcessService;

	@Autowired
	private IPolicyDrawMaterialService policyDrawMaterialService;

	@Autowired
	private IEnterpriseService enterpriseService;

	@Autowired
	private IDictItemService dictItemService;

	@Autowired
	private IPolicyService policyService;

	@Override
	public IPage<PolicyDrawVO> selectPolicyDrawPage(IPage<PolicyDrawVO> page, PolicyDrawVO policyDraw) {
		return page.setRecords(baseMapper.selectPolicyDrawPage(page, policyDraw));
	}

	@Override
	@Transactional
	public boolean saveAll(PolicyDrawVO policyDraw) {
		List<Long> collect = policyDraw.getPolicyList().stream().map(Policy::getId).collect(Collectors.toList());
		String policys = "";
		for (Long id : collect) {
			if (Func.isBlank(policys)) {
				policys = id + "";
			} else {
				policys += "," + id;
			}
		}
		policyDraw.setPolicys(policys);
		if (saveOrUpdate(policyDraw)) {
			policyDrawMaterialService.delete(policyDraw.getId());
			if (policyDraw.getMaterialList() != null && policyDraw.getMaterialList().size() != 0) {
				policyDraw.getMaterialList().forEach(i -> i.setMatterId(policyDraw.getId()));
				System.out.println(policyDraw.getId());
				policyDrawMaterialService.saveOrUpdateBatch(policyDraw.getMaterialList());
			}
			policyDrawProcessService.delete(policyDraw.getId());
			if (policyDraw.getProcessesList() != null && policyDraw.getProcessesList().size() != 0) {
				policyDraw.getProcessesList().forEach(i -> i.setMatterId(policyDraw.getId()));
				policyDrawProcessService.saveOrUpdateBatch(policyDraw.getProcessesList());
			}
			return true;
		} else {
			return false;
		}
	}
	@Override
	public List<PolicyPushVO> selectPushPolicyPage(String enterpriseCode) throws Exception{
		List<SgaPolicyDrawPushVo> drawPushVos=this.selectPushPage(enterpriseCode);
		List<Long> policyIds=new ArrayList<>();
		policyIds=drawPushVos.stream().map(SgaPolicyDrawPushVo::getPolicys).map(i->i.split(",")).flatMap(Arrays::stream).filter(s -> !s.isEmpty()).map(Long::parseLong).collect(Collectors.toList());
		LambdaQueryWrapper<Policy> lambdaQueryWrapper=new LambdaQueryWrapper<>();
		lambdaQueryWrapper.in(!drawPushVos.isEmpty(),Policy::getId,policyIds);
		List<Policy> policies = policyService.list(lambdaQueryWrapper);
		List<PolicyPushVO> policyPushVOS=new ArrayList<>();
		policies.forEach(policy -> {
			PolicyPushVO policyPushVO=new PolicyPushVO(policy);
			//把匹配度最大的draw的匹配度赋给政策
			Optional<SgaPolicyDrawPushVo> maxSimilarityVo = drawPushVos.stream()
				.filter(i -> i.getPolicys().contains(policy.getId() + ""))
				.max(Comparator.comparing(SgaPolicyDrawPushVo::getSimilarity));

			if (maxSimilarityVo.isPresent()) {
				policyPushVO.setSimilarity(maxSimilarityVo.get().getSimilarity());
			} else {
				// 处理无符合条件元素的情况，如抛出异常、设置默认值或记录日志等
				throw new NoSuchElementException("No DrawPushVo with matching policy ID and non-zero similarity found");
			}
			policyPushVOS.add(policyPushVO);

		});
		policyPushVOS.sort(Comparator.comparing(PolicyPushVO::getSimilarity).reversed());
		return policyPushVOS;
	}
	@Override
	public List<SgaPolicyDrawPushVo> selectPushPage(String enterpriseCode) throws Exception{
		List<PolicyDraw> policyDraws = this.list(new LambdaQueryWrapper<PolicyDraw>().eq(PolicyDraw::getStatus, 1).in(PolicyDraw::getPublishStatus, 5, 6));
		EnterpriseVO enterprise = enterpriseService.getEnterpriseByCode(enterpriseCode);
		List<DictItem> dictItems = dictItemService.getList("label_weight");
		List<SgaPolicyDrawPushVo> polictDrawPushVos=new ArrayList<>();
		//匹配度
		double similarity=0;
		//阈值
		double threshold=Double.valueOf(dictItemService.getLabel("label_threshold", "1"));
		for (PolicyDraw policyDraw : policyDraws) {
			for (DictItem dictItem : dictItems){
				Field policyDrawField = policyDraw.getClass().getDeclaredField(dictItem.getLabel());
				Field enterpriseField = enterprise.getClass().getSuperclass().getDeclaredField(dictItem.getLabel());
				policyDrawField.setAccessible(true);
				enterpriseField.setAccessible(true);
				if(policyDrawField.get(policyDraw)==null || enterpriseField.get(enterprise)==null){
					continue;
				}
				String policyDrawLable=policyDrawField.get(policyDraw).toString();
				String enterpriseLable=enterpriseField.get(enterprise).toString();
				String[] enterpriseLables = enterpriseLable.split(",");
				String[] policyDrawLables = policyDrawLable.split(",");
				Set<String> set1 = new HashSet<String>(Arrays.asList(enterpriseLables));
				Set<String> set2 = new HashSet<String>(Arrays.asList(policyDrawLables));
				similarity = similarity+(calculateJaccardSimilarity(set1,set2)*Double.valueOf(dictItem.getDescription()));
			}
			if(similarity<threshold){
				continue;
			}
			SgaPolicyDrawPushVo policyDrawPushVo=new SgaPolicyDrawPushVo(policyDraw);
			policyDrawPushVo.setSimilarity(similarity);
			polictDrawPushVos.add(policyDrawPushVo);
			similarity=0;
		}
		polictDrawPushVos.sort(Comparator.comparing(SgaPolicyDrawPushVo::getSimilarity).reversed());
		return polictDrawPushVos;

	}
	public static double calculateJaccardSimilarity(Set<String> set1, Set<String> set2) {
		Set<String> intersection = new HashSet<>(set1);
		intersection.retainAll(set2);  // 计算交集
		Set<String> union = new HashSet<>(set1);
		union.addAll(set2);            // 计算并集
		return (double) intersection.size() / union.size();
	}
	@Override
	public List<EnterprisePushVO> selectPushEnterprise(String policyDrawId) throws Exception{
		LambdaQueryWrapper<Enterprise> wrapper=new LambdaQueryWrapper<>();
		wrapper.or(
			w->{
				w.isNotNull(Enterprise::getEnterpriseScale);
				w.isNotNull(Enterprise::getEnterpriseSpecial);
				w.isNotNull(Enterprise::getIndustryType);
				w.isNotNull(Enterprise::getEnterpriseTalent);
				w.isNotNull(Enterprise::getEnterpriseQualification);
				w.isNotNull(Enterprise::getQualificationLevel);
				w.isNotNull(Enterprise::getCreditRating);
				w.isNotNull(Enterprise::getListingAddress);
				w.isNotNull(Enterprise::getTechnicalCapability);
				w.isNotNull(Enterprise::getProjectType);
			});
		List<Enterprise> enterpriseList=enterpriseService.list(wrapper);
		PolicyDraw policyDraw=this.getById(policyDrawId);
		List<DictItem> dictItems = dictItemService.getList("label_weight");
		List<EnterprisePushVO> enterprisePushVOs=new ArrayList<>();
		//匹配度
		double similarity=0;
		//阈值
		double threshold=Double.valueOf(dictItemService.getLabel("label_threshold", "1"));
		for (Enterprise enterprise : enterpriseList) {
			for (DictItem dictItem : dictItems){
				Field policyDrawField = policyDraw.getClass().getDeclaredField(dictItem.getLabel());
				Field enterpriseField = enterprise.getClass().getDeclaredField(dictItem.getLabel());
				policyDrawField.setAccessible(true);
				enterpriseField.setAccessible(true);
				if(policyDrawField.get(policyDraw)==null || enterpriseField.get(enterprise)==null){
					continue;
				}
				String policyDrawLable=policyDrawField.get(policyDraw).toString();
				String enterpriseLable=enterpriseField.get(enterprise).toString();
				String[] enterpriseLables = enterpriseLable.split(",");
				String[] policyDrawLables = policyDrawLable.split(",");
				Set<String> set1 = new HashSet<String>(Arrays.asList(enterpriseLables));
				Set<String> set2 = new HashSet<String>(Arrays.asList(policyDrawLables));
				similarity = similarity+(calculateJaccardSimilarity(set1,set2)*Double.valueOf(dictItem.getDescription()));
			}
			if(similarity<threshold){
				continue;
			}
			EnterprisePushVO enterprisePushVO=new EnterprisePushVO(enterprise);
			enterprisePushVO.setSimilarity(similarity);
			enterprisePushVOs.add(enterprisePushVO);
			similarity=0;
		}
		return enterprisePushVOs;
	}
	public Boolean sendPush(PolicyDrawPushVO policyDrawPushVO) throws Exception{
		// 电话号码验证正则表达式
		Pattern PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");

		List<Enterprise> enterpriseList=enterpriseService.listByIds(policyDrawPushVO.getIds());
		List<String> mobiles=enterpriseList.stream()
			.flatMap(enterprise -> Stream.of(enterprise.getMobilePhone(), enterprise.getLinkPhone())
				.filter(Objects::nonNull)
				.filter(phone -> PHONE_PATTERN.matcher(phone).matches()))
			.collect(Collectors.toList());
		String mobileStr=String.join(",", mobiles);
		Map<String,String> map=new HashMap<>();
		map.put("mobiles",mobileStr);
		map.put("content",policyDrawPushVO.getContent());
		String res=MASUtil.SendSms(map);
		JSON json = JSONUtil.parseObj(res);
		return json.getByPath("success").toString().equals("true");
	}
}
